using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace AntEater.ComponentModel
{
    /// <summary>
    /// Represents a collection of tracked objects.
    /// </summary>
    internal class TrackedObjectsCollection : KeyedCollection<INotifyPropertyChanged, TrackingData>
    {
        /// <summary>
        /// Occurs when the collection changed.
        /// </summary>
        public event EventHandler<CollectionChangeEventArgs> CollectionChanged;

        /// <summary>
        /// Inserts an element into the <see cref="T:System.Collections.ObjectModel.Collection`1"></see> at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index at which item should be inserted.</param>
        /// <param name="item">The object to insert. The value can be null for reference types.</param>
        /// <exception cref="T:System.ArgumentOutOfRangeException">index is less than zero.-or-index is greater than <see cref="P:System.Collections.ObjectModel.Collection`1.Count"></see>.</exception>
        protected override void InsertItem(int index, TrackingData item) {

            base.InsertItem(index, item);

            this.OnCollectionChanged(CollectionChangeAction.Add);
        }

        /// <summary>
        /// Replaces the element at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index of the element to replace.</param>
        /// <param name="item">The new value for the element at the specified index. The value can be null for reference types.</param>
        /// <exception cref="T:System.ArgumentOutOfRangeException">index is less than zero.-or-index is greater than <see cref="P:System.Collections.ObjectModel.Collection`1.Count"></see>.</exception>
        protected override void SetItem(int index, TrackingData item) {

            base.SetItem(index, item);

            this.OnCollectionChanged(CollectionChangeAction.Refresh);
        }

        /// <summary>
        /// Removes the element at the specified index of the <see cref="T:System.Collections.ObjectModel.Collection`1"></see>.
        /// </summary>
        /// <param name="index">The zero-based index of the element to remove.</param>
        /// <exception cref="T:System.ArgumentOutOfRangeException">index is less than zero.-or-index is equal to or greater than <see cref="P:System.Collections.ObjectModel.Collection`1.Count"></see>.</exception>
        protected override void RemoveItem(int index) {

            base.RemoveItem(index);

            this.OnCollectionChanged(CollectionChangeAction.Remove);
        }

        /// <summary>
        /// Removes all elements from the <see cref="T:System.Collections.ObjectModel.Collection`1"></see>.
        /// </summary>
        protected override void ClearItems() {

            base.ClearItems();

            this.OnCollectionChanged(CollectionChangeAction.Refresh);
        }

        /// <summary>
        /// Called when [collection changed].
        /// </summary>
        /// <param name="action">The action.</param>
        protected void OnCollectionChanged(CollectionChangeAction action) {
            if (CollectionChanged != null) {
                CollectionChanged(this, new CollectionChangeEventArgs(action, this));
            }
        }

        /// <summary>
        /// When implemented in a derived class, extracts the key from the specified element.
        /// </summary>
        /// <param name="item">The element from which to extract the key.</param>
        /// <returns>The key for the specified element.</returns>
        protected override INotifyPropertyChanged GetKeyForItem(TrackingData item) {
            return item.TrackedObject;
        }
    }
}
